package com.android.love.net;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.text.TextUtils;

import com.android.love.util.FileUtil;
import com.android.love.util.LogUtil;
import com.squareup.okhttp.OkHttpClient;

/**
 * 联网引擎，具体去请求网络
 * 
 * @author adison
 * 
 */
public class HttpAgent {
	private final static String TAG = "HttpAgent";
	private Context context;
	private HttpURLConnection connection;
	public static final int TIMEOUT = 5;
	// public static final int FIRST_TIMEOUT = 5;
	// public static final int SECOND_TIMEOUT = 3;
	private static final String METHOD_POST = "POST";
	private static final String METHOD_GET = "GET";
	private static final String USER_AGENT = "Android_brunjoy";
	private static HttpAgent agent;
	private static final String DEFAULT_CHARSET = "UTF-8";

	// public HttpAgent(Context context) {
	// this.context = context;
	// }
	private HttpAgent() {
	};

	public synchronized static HttpAgent getInstance() {
		if (agent == null)
			agent = new HttpAgent();
		return agent;
	}

	//
	// /**
	// * get请求
	// *
	// * @param url
	// * @param pramers
	// * 请求参数
	// * @param values
	// * @return
	// */
	// public synchronized String[] requestByGet(String url, int requestOrder) {
	// // 设为后台线程
	// android.os.Process
	// .setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
	// // HttpURLConnection connection = null;
	// try {
	// // paramHttp(url, "GET");
	// connection = paramHttp(url, "GET", requestOrder);
	// connection.connect();
	// int httpCode = connection.getResponseCode();
	// InputStream in = connection.getInputStream();
	// String jsonStr = new String(FileUtil.load(in), "UTF-8");
	// LogUtil.i(TAG, "httpCode" + httpCode + "--test" + jsonStr);
	// if (!"".equals(jsonStr)) {
	// JSONObject json = new JSONObject(jsonStr);
	// return new String[] { httpCode + "", json.toString() };
	// }
	// } catch (MalformedURLException e) {
	// e.printStackTrace();
	// } catch (IOException e) {
	// e.printStackTrace();
	// } catch (JSONException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// } finally {
	// shutdownHttpConnection();
	// }
	// return null;
	// }
	//
	// /**
	// * 通过get方式获取byte数据
	// *
	// * @param url
	// * @param method
	// * @return
	// */
	// public synchronized byte[] getByteData(String url, int requestOrder) {
	// try {
	// connection = paramHttp(url, "GET", requestOrder);
	// connection.connect();
	// InputStream in = connection.getInputStream();
	// byte[] bs = FileUtil.load(in);
	// return bs;
	// } catch (MalformedURLException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// } catch (IOException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// return null;
	//
	// }
	//
	// /**
	// * 配置请求参数
	// *
	// * @param url
	// * @param method
	// * @return
	// * @throws MalformedURLException
	// * @throws IOException
	// */
	// private HttpURLConnection paramHttp(String url, String method,
	// int requestOrder) throws MalformedURLException, IOException {
	// URL uri = new URL(url);
	// // 打开连接
	// connection = (HttpURLConnection) uri.openConnection();
	// // 设置是否从httpUrlConnection读入，默认情况下是true;
	// connection.setDoInput(true);
	// if (requestOrder == 0) {
	// connection.setConnectTimeout(FIRST_TIMEOUT * 1000);// 设置连接主机超时
	// connection.setReadTimeout(FIRST_TIMEOUT * 1000);// 设置从主机读取数据超时
	// } else if (requestOrder == 1) {
	// connection.setConnectTimeout(SECOND_TIMEOUT * 1000);// 设置连接主机超时
	// connection.setReadTimeout(SECOND_TIMEOUT * 1000);// 设置从主机读取数据超时
	// }
	// connection.setRequestMethod(method);// 设置请求方法,post/get
	// return connection;
	// }
	//
	// // 关闭连接管理器并释放资源
	// public void shutdownHttpConnection() {
	// if (connection != null) {
	// connection.disconnect();
	// connection = null;
	// }
	// }

	/**
	 * 执行HTTP POST请求。
	 * 
	 * @param context
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @param headers
	 * 
	 * @param charset
	 *            字符集，如UTF-8, GBK, GB2312
	 * 
	 * @return 响应码+响应字符串
	 * @throws IOException
	 */
	private String[] doPost(String url, Map<String, String> params,
			Map<String, String> headers, String charset, int connectTimeout,
			int readTimeout) throws Exception {
		String ctype = "application/x-www-form-urlencoded;charset=" + charset;
		String query = buildQuery(params, charset);
		LogUtil.d(TAG, "doPost  buildQuery =" + query);
		byte[] content = {};
		if (query != null) {
			content = query.getBytes(charset);
		}
		return doPost(url, ctype, content, headers, connectTimeout, readTimeout);
	}

	public String[] doPost(String url, Map<String, String> params)
			throws Exception {
		return doPost(url, params, null, DEFAULT_CHARSET, TIMEOUT, TIMEOUT);
	}

	/**
	 * 执行HTTP POST请求。
	 * 
	 * @param context
	 * 
	 * @param url
	 *            请求地址
	 * @param ctype
	 *            请求类型
	 * @param content
	 *            请求字节数组
	 * @param headers
	 *            请求header
	 * 
	 * @return 响应码+响应字符串
	 * @throws IOException
	 */
	private String[] doPost(String url, String ctype, byte[] content,
			Map<String, String> headers, int connectTimeout, int readTimeout)
			throws Exception {
		HttpURLConnection conn = null;
		OutputStream os = null;
		DataOutputStream out = null;
		String rsp = null;
		try {
			try {
				conn = getConnection(new URL(url.startsWith("http") ? url
						: (UriHelper.REALM_NAME + url)), METHOD_POST, ctype);
				if (headers != null) {
					Set<Entry<String, String>> set = headers.entrySet();
					for (Entry<String, String> entry : set) {
						conn.addRequestProperty(entry.getKey(),
								entry.getValue());
					}
				}
				conn.setConnectTimeout(connectTimeout);
				conn.setReadTimeout(readTimeout);
			} catch (IOException e) {
				return new String[] { conn.getResponseCode() + "",
						e.getMessage() };
				// throw new IOException(getResposeMsg(conn, e.getMessage()));
			}
			try {
				os = conn.getOutputStream();
				out = new DataOutputStream(os);
				out.write(content);
				rsp = getResponseAsString(conn);
				LogUtil.d(TAG, "rsp=" + rsp);
			} catch (Exception e) {

				throw e;
			}

		} finally {
			if (os != null) {
				os.close();
			}
			if (out != null) {
				out.close();
			}
			if (conn != null) {
				conn.disconnect();
			}
		}
		// MyLog.d( TAG, "date=" + rsp );
		return new String[] { conn.getResponseCode() + "", rsp };
	}

	/**
	 * 组织参数
	 * 
	 * @param params
	 * @param charset
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public String buildQuery(Map<String, String> params, String charset)
			throws UnsupportedEncodingException {
		if (params == null || params.isEmpty()) {
			return null;
		}
		if (TextUtils.isEmpty(charset)) {
			charset = DEFAULT_CHARSET;
		}

		StringBuilder query = new StringBuilder();
		Set<Entry<String, String>> entries = params.entrySet();
		boolean hasParam = false;

		for (Entry<String, String> entry : entries) {
			String name = entry.getKey();
			String value = entry.getValue();
			// 忽略参数名或参数值为空的参数
			if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(value)) {
				if (hasParam) {
					query.append("&");
				} else {
					hasParam = true;
				}

				query.append(name).append("=")
						.append(URLEncoder.encode(value, charset));
			}
		}

		return query.toString();
	}

	/**
	 * 得到HttpURLConnection
	 * 
	 * @param url
	 * @param method
	 * @param ctype
	 * @return
	 * @throws IOException
	 */
	private HttpURLConnection getConnection(URL url, String method, String ctype)
			throws IOException {
		OkHttpClient client = new OkHttpClient();
		HttpURLConnection conn = null;
		if ("https".equals(url.getProtocol())) {
			SSLContext ctx = null;
			try {
				ctx = SSLContext.getInstance("TLS");
				ctx.init(new KeyManager[0],
						new TrustManager[] { new DefaultTrustManager() },
						new SecureRandom());
			} catch (Exception e) {
				throw new IOException(e.getMessage());
			}
			HttpsURLConnection connHttps = null;
			// if (proxy == null) {
			connHttps = (HttpsURLConnection) url.openConnection();
			// } else {
			// connHttps = (HttpsURLConnection) url.openConnection( proxy );
			// }
			connHttps.setSSLSocketFactory(ctx.getSocketFactory());
			connHttps.setHostnameVerifier(new HostnameVerifier() {
				public boolean verify(String hostname, SSLSession session) {
					return true;// 默认都认证通过
				}
			});
			conn = connHttps;
		} else {
			conn = client.open(url);
			// conn = (HttpURLConnection) url.openConnection();
		}
		conn.setRequestMethod(method);
		conn.setDoInput(true);
		conn.setUseCaches(false);
		conn.setDoOutput(METHOD_POST.equals(method));
		conn.setRequestProperty("Accept", "text/xml,text/javascript,text/html");
		conn.setRequestProperty("User-Agent", USER_AGENT);
		conn.setRequestProperty("Content-Type", ctype);
		conn.setRequestProperty("Accept-Encoding", "gzip");// support gzip

		return conn;
	}

	/**
	 * @param conn
	 * @return
	 * @throws IOException
	 */
	protected String getResponseAsString(HttpURLConnection conn)
			throws IOException {
		String charset = getResponseCharset(conn.getContentType());
		String header = conn.getHeaderField("Content-Encoding");
		boolean isGzip = false;
		if (header != null
				&& header.toLowerCase(Locale.getDefault()).contains("gzip")) {
			isGzip = true;
		}
		InputStream es = conn.getErrorStream();
		if (es == null) {
			InputStream input = conn.getInputStream();
			if (isGzip) {
				input = new GZIPInputStream(input);
			}
			return getStreamAsString(input, charset);
		} else {
			if (isGzip) {
				es = new GZIPInputStream(es);
			}
			String msg = getStreamAsString(es, charset);
			if (TextUtils.isEmpty(msg)) {
				// return conn.getResponseMessage();
				throw new IOException("ResponseCode=" + conn.getResponseCode()
						+ ",ResponseMessage=" + conn.getResponseMessage());
				// } else if (responseError) {
				// return msg;
			} else

			{
				throw new IOException(msg);
			}
		}
	}

	private String getStreamAsString(InputStream stream, String charset)
			throws IOException {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					stream, charset));
			StringWriter writer = new StringWriter();

			char[] chars = new char[256];
			int count = 0;
			while ((count = reader.read(chars)) > 0) {
				writer.write(chars, 0, count);
			}
			return writer.toString();
		} finally {
			if (stream != null) {
				stream.close();
			}
		}
	}

	private String getResponseCharset(String ctype) {
		String charset = DEFAULT_CHARSET;

		if (!TextUtils.isEmpty(ctype)) {
			String[] params = ctype.split(";");
			for (String param : params) {
				param = param.trim();
				if (param.startsWith("charset")) {
					String[] pair = param.split("=", 2);
					if (pair.length == 2) {
						if (!TextUtils.isEmpty(pair[1])) {
							charset = pair[1].trim();
						}
					}
					break;
				}
			}
		}

		return charset;
	}

	private class DefaultTrustManager implements X509TrustManager {
		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}

		public void checkClientTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
		}

		public void checkServerTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
		}
	}

	/**
	 * 执行HTTP GET请求。
	 * 
	 * @param context
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * 
	 * @return 响应码+响应字符串
	 * @throws IOException
	 */
	public String[] doGet(String url, Map<String, String> params)
			throws IOException {
		return doGet(url, params, DEFAULT_CHARSET);
	}

	/**
	 * 执行HTTP GET请求。
	 * 
	 * @param context
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @param charset
	 *            字符集，如UTF-8, GBK, GB2312
	 * 
	 * @return 响应码+响应字符串
	 * @throws IOException
	 */
	private String[] doGet(String url, Map<String, String> params,
			String charset) throws IOException {
		HttpURLConnection conn = null;
		String rsp = null;
		long time = System.currentTimeMillis();
		try {
			String ctype = "application/x-www-form-urlencoded;charset="
					+ charset;
			// String ctype = "text/xml;charset=" + charset;
			String query = buildQuery(params, charset);
			try {
				
				LogUtil.i(TAG, "get---url---"+buildGetUrl(url, query).toString());
				conn = getConnection(buildGetUrl(url, query), METHOD_GET, ctype);
			} catch (IOException e) {
				LogUtil.i(TAG, "IOException---" + e.getMessage());
				e.printStackTrace();
			}

			try {
				if (conn == null)
					return null;
				rsp = getResponseAsString(conn);
			} catch (IOException e) {
				// rsp = getResposeMsg(conn, e.getMessage());
				// throw new IOException(getResposeMsg(conn, e.getMessage()));
				return new String[] { conn.getResponseCode() + "",
						e.getMessage() };
			} catch (Exception e) {
				e.printStackTrace();
			}
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
		}
		LogUtil.i(
				TAG,
				"do get url=" + url + " 耗时:"
						+ (System.currentTimeMillis() - time) + " "
						+ conn.getURL());
		LogUtil.i(TAG, "get date=" + rsp);
		return new String[] { conn.getResponseCode() + "", rsp };
	}

	/**
	 * 组织get请求url
	 * 
	 * @param strUrl
	 * @param query
	 * @return
	 * @throws IOException
	 */
	private URL buildGetUrl(String strUrl, String query) throws IOException {
		URL url = new URL(strUrl.startsWith("http") ? strUrl
				: (UriHelper.REALM_NAME + strUrl));
		if (TextUtils.isEmpty(query)) {
			return url;
		}

		if (TextUtils.isEmpty(url.getQuery())) {
			if (strUrl.endsWith("?")) {
				strUrl = strUrl + query;
			} else {
				strUrl = strUrl + "?" + query;
			}
		} else {
			if (strUrl.endsWith("&")) {
				strUrl = strUrl + query;
			} else {
				strUrl = strUrl + "&" + query;
			}
		}

		return new URL(strUrl.startsWith("http") ? strUrl
				: (UriHelper.REALM_NAME + strUrl));
	}

	/**
	 * post请求
	 * 
	 * @param url
	 * @param pramers
	 *            请求参数
	 * @param values
	 * @return
	 */
	public synchronized String[] requestByPost(String url,
			Map<String, String> params, int requestOrder) {
		// 设为后台线程
		android.os.Process
				.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
		// HttpURLConnection connection = null;
		try {
			paramHttp(url, "POST", requestOrder);
			// URL postUrl = new URL(url);
			// // 打开连接
			// connection = (HttpURLConnection) postUrl.openConnection();
			// 设置是否向connection输出，因为这个是post请求，参数要放在 http正文内，因此需要设为true
			connection.setDoOutput(true);
			// // 设置是否从httpUrlConnection读入，默认情况下是true;
			// Post 请求不能使用缓存
			connection.setUseCaches(false);
			// URLConnection.setFollowRedirects是static函数，作用于所有的URLConnection对象。
			HttpURLConnection.setFollowRedirects(true);
			// URLConnection.setInstanceFollowRedirects是成员函数，仅作用于当前函数
			connection.setInstanceFollowRedirects(true);
			// 设定传送的内容类型是可序列化的java对象
			// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
			connection.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded");
			// 连接，从postUrl.openConnection()至此的配置必须要在connect之前完成，
			// 要注意的是connection.getOutputStream会隐含的进行connect。
			connection.connect();
			OutputStream os = connection.getOutputStream();
			DataOutputStream out = new DataOutputStream(os);
			// 正文，正文内容其实跟get的URL中'?'后的参数字符串一致
			String query = buildQuery(params, "utf-8");
			LogUtil.e(TAG, "query---"+query);
			String content = query;
			// DataOutputStream.writeBytes将字符串中的16位的unicode字符以8位的字符形式写道流里面
			out.writeBytes(content);

			out.flush();
			out.close(); // flush and close
			os.close();
			int httpCode = connection.getResponseCode();
			InputStream in = connection.getInputStream();
			String jsonStr = new String(FileUtil.load(in), "UTF-8");
			LogUtil.i(TAG, "httpCode" + httpCode + "--test---" + jsonStr);
			if (!"".equals(jsonStr)) {
				JSONObject json = new JSONObject(jsonStr);
				LogUtil.i(TAG, "json---" + json.toString());
				return new String[] { httpCode + "", json.toString() };
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			shutdownHttpConnection();
		}
		return null;
	}

	/**
	 * 配置请求参数
	 * 
	 * @param url
	 * @param method
	 * @return
	 * @throws MalformedURLException
	 * @throws IOException
	 */
	private HttpURLConnection paramHttp(String uri, String method,
			int requestOrder) throws MalformedURLException, IOException {
		OkHttpClient client = new OkHttpClient();
		// URL uri = new URL(url);
		// client.open(url);
		// 打开连接
		// connection = (HttpURLConnection) uri.openConnection();
		URL url = new URL(uri);
		connection = client.open(url);
		// 设置是否从httpUrlConnection读入，默认情况下是true;
		connection.setDoInput(true);
		if (requestOrder == 0) {
			connection.setConnectTimeout(TIMEOUT * 1000);// 设置连接主机超时
			connection.setReadTimeout(TIMEOUT * 1000);// 设置从主机读取数据超时
		} else if (requestOrder == 1) {
			connection.setConnectTimeout(TIMEOUT * 1000);// 设置连接主机超时
			connection.setReadTimeout(TIMEOUT * 1000);// 设置从主机读取数据超时
		}
		connection.setRequestMethod(method);// 设置请求方法,post/get
		return connection;
	}

	// 关闭连接管理器并释放资源
	public void shutdownHttpConnection() {
		if (connection != null) {
			connection.disconnect();
			connection = null;
		}
	}

}
